#include <proc.h>
#include <elf.h>
#include <fs.h>

#ifdef __LP64__
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Phdr Elf64_Phdr
#else
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Phdr Elf32_Phdr
#endif


static uintptr_t loader(PCB *pcb, const char *filename) {
//  size_t ramdisk_read(void *buf, size_t offset, size_t len);
//  size_t get_ramdisk_size();
  size_t fs_ltell(int fd);
  int fd; 
  int len;

  fd = fs_open(filename,0,0);
//  printf("fd:%d\n",fd);
   
//  ramdisk_read(pbuff,0,ramdisk_size);
  fs_lseek(fd, 0, SEEK_END);
  len = fs_ltell(fd);
  char*  pbuff=(char *)malloc(len*sizeof(char));

  fs_lseek(fd, 0, SEEK_SET);
  fs_read(fd,pbuff,len);

  Elf_Ehdr* pfilehead = (Elf_Ehdr*)pbuff;
  Elf_Phdr* pproheader = (Elf_Phdr*)(pbuff + pfilehead->e_phoff);
//  printf("entry:%lx\n ",pfilehead->e_entry);
//  printf("Number of program heads:%d,program offset: %d\n", pfilehead->e_phnum, pfilehead->e_phoff);
 // printf("eident:%lx",*(uint32_t *)pfilehead->e_ident);
  assert(*(uint32_t *)pfilehead->e_ident == 0x464c457f);
  for (int i = 0;i<pfilehead->e_phnum;++i){
    //type
    int file_sz = 0;
    int mem_size = 0;
    switch(pproheader[i].p_type)
    {  case PT_LOAD : 
//	printf("offset:%x,vaddr:%lx,paddr:%lx,file_size:%x,memory_size:%x\n",pproheader[i].p_offset,pproheader[i].p_vaddr,pproheader[i].p_paddr,pproheader[i].p_filesz,pproheader[i].p_memsz);
//	memcpy(pproheader[i].p_paddr,pbuff+pproheader[i].p_offset);
//       printf("%x\n",*(pbuff + pproheader[i].p_offset));
       while (file_sz <  pproheader[i].p_filesz){
         *(volatile uint8_t *)(pproheader[i].p_paddr+file_sz) = *(pbuff + pproheader[i].p_offset + file_sz);
	 file_sz += 1;
       }
       mem_size = file_sz;
       while (mem_size <  pproheader[i].p_memsz){
      //   *(volatile uint8_t *)(pproheader[i].p_paddr+mem_size) = *(pbuff + pproheader[i].p_offset + mem_size);

         *(volatile uint8_t *)(pproheader[i].p_paddr+mem_size) = 0;
	mem_size += 1;
       }
       break;
     default : break;
    }
  
  }
  fs_close(fd);
  return pfilehead->e_entry;
}

void naive_uload(PCB *pcb, const char *filename) {
  uintptr_t entry = loader(pcb, filename);
 /* int fp;
  char * pbuff = (char *)malloc(4 * sizeof(char));
  fp = fs_open("/share/files/num",0,0);
  assert(fp);
  fs_lseek(fp, 5 * 500,SEEK_SET);
  int i;
  for(i = 500; i<501;i++){
    fs_read(fp,n,4);
    printf("fs_read:%d",pbuff);
  } 
  fs_write(fp,pbuff,1);
  */
  Log("Jump to entry = %p", entry);
  ((void(*)())entry) ();
}


